<html>
<head><meta charset="utf-8"><title>Dropping unused lock inside if let · t-compiler/wg-mir-opt · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/index.html">t-compiler/wg-mir-opt</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html">Dropping unused lock inside if let</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="218873531"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218873531" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Christian Poveda <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218873531">(Dec 04 2020 at 18:33)</a>:</h4>
<p>Hi everyone, someone showed me this snippet of code that doesn't compile: <a href="https://play.integer32.com/?version=stable&amp;mode=release&amp;edition=2018&amp;gist=3396ab547a96ec73b1983b79ebe5f49e">https://play.integer32.com/?version=stable&amp;mode=release&amp;edition=2018&amp;gist=3396ab547a96ec73b1983b79ebe5f49e</a></p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">sync</span>::<span class="n">RwLock</span><span class="p">;</span><span class="w"></span>

<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">foo</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="kt">u32</span><span class="p">,</span><span class="w"> </span><span class="kt">u32</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span>: <span class="nc">RwLock</span><span class="o">&lt;</span><span class="nb">Result</span><span class="o">&lt;</span><span class="kt">u32</span><span class="p">,</span><span class="w"> </span><span class="kt">u32</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">RwLock</span>::<span class="n">new</span><span class="p">(</span><span class="nb">Err</span><span class="p">(</span><span class="mi">5</span><span class="p">));</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="n">a</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="n">unwrap</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="o">*</span><span class="n">a</span><span class="p">.</span><span class="n">write</span><span class="p">().</span><span class="n">unwrap</span><span class="p">()</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="mi">6</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>

<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="n">a</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="n">x</span><span class="p">.</span><span class="n">clone</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>I wanted to know if there's something wrong with dropping the first read lock just after jumping to the next basic block instead of dropping it after the <code>if let</code> expression.</p>



<a name="218893183"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893183" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Noah Lev <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893183">(Dec 04 2020 at 21:26)</a>:</h4>
<p>What do you mean by "it doesn't compile"? I clicked the Playground link you included and it compiles fine.</p>



<a name="218893205"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893205" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Noah Lev <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893205">(Dec 04 2020 at 21:26)</a>:</h4>
<div class="codehilite"><pre><span></span><code>Compiling playground v0.0.1 (/playground)
    Finished release [optimized] target(s) in 0.60s
</code></pre></div>



<a name="218893222"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893222" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893222">(Dec 04 2020 at 21:26)</a>:</h4>
<p>I assume this panics because of the double lock</p>



<a name="218893243"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893243" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Noah Lev <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893243">(Dec 04 2020 at 21:27)</a>:</h4>
<p>So it fails <em>at runtime</em>?</p>



<a name="218893269"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893269" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893269">(Dec 04 2020 at 21:27)</a>:</h4>
<p>but I think that this can't be "fixed" because drop order is fixed by the language</p>



<a name="218893351"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893351" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Noah Lev <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893351">(Dec 04 2020 at 21:28)</a>:</h4>
<p>Actually it hangs on the Playground...</p>



<a name="218893501"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893501" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893501">(Dec 04 2020 at 21:29)</a>:</h4>
<p>it's deadlocked?</p>



<a name="218893605"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893605" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> scottmcm <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893605">(Dec 04 2020 at 21:30)</a>:</h4>
<p>Hmm, is <code>RwLock</code> upgradable?  It's not clear at all to me that using only temporary guards here is correct -- something else could have changed it between the read and write, no?</p>



<a name="218893685"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893685" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> scottmcm <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893685">(Dec 04 2020 at 21:31)</a>:</h4>
<p>(But I never remember the details of temporary lifetimes, and whether this would be fixed by using a <code>match</code> instead, or similar weird edge cases...)</p>



<a name="218893895"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218893895" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218893895">(Dec 04 2020 at 21:33)</a>:</h4>
<blockquote>
<p>I wanted to know if there's something wrong with dropping the first read lock just after jumping to the next basic block instead of dropping it after the if let expression.</p>
</blockquote>
<p>You'll have to convince the language team, not wg-mir-opt, as this is simply how lifetimes in <code>match</code> expressions are specified to behave. Changing that would be a subtle breaking change to the language semantics.</p>



<a name="218894026"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218894026" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218894026">(Dec 04 2020 at 21:34)</a>:</h4>
<p>This isn't about lifetimes, it's about drop rules</p>



<a name="218894173"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218894173" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218894173">(Dec 04 2020 at 21:36)</a>:</h4>
<p>The range of code between an object's creation and its destructor getting invoked is generally called the object's lifetime</p>



<a name="218894185"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218894185" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218894185">(Dec 04 2020 at 21:36)</a>:</h4>
<p>Certainly the lifetime for temporaries in the scrutinee have to extend to after the match in at least some cases, and so that's where the drop glue goes; after NLL and other such lifetime improvements the drop glue did not move because that would change the language's observable behavior</p>



<a name="218894272"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218894272" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218894272">(Dec 04 2020 at 21:36)</a>:</h4>
<p>The intended behavior here is also explained in the reference: <a href="https://doc.rust-lang.org/reference/destructors.html#temporary-scopes">https://doc.rust-lang.org/reference/destructors.html#temporary-scopes</a></p>
<p>Specifically, it calls out:</p>
<blockquote>
<p>The scrutinee of a match expression is not a temporary scope, so temporaries in the scrutinee can be dropped after the match expression. For example, the temporary for 1 in match 1 { ref mut z =&gt; z }; lives until the end of the statement.</p>
</blockquote>



<a name="218894949"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218894949" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Christian Poveda <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218894949">(Dec 04 2020 at 21:43)</a>:</h4>
<p>yes my bad, it compiles but deadlocks.</p>



<a name="218896864"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218896864" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218896864">(Dec 04 2020 at 22:02)</a>:</h4>
<p>You can fix the deadlock by writing <code>{let g = a.read().unwrap(); *g}</code> in the if statement to force the temporary to be dropped</p>



<a name="218946532"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218946532" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Josh Triplett <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218946532">(Dec 05 2020 at 18:23)</a>:</h4>
<p>That doesn't fix the locking semantics, though.</p>



<a name="218946578"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/189540-t-compiler/wg-mir-opt/topic/Dropping%20unused%20lock%20inside%20if%20let/near/218946578" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Josh Triplett <a href="https://rust-lang.github.io/zulip_archive/stream/189540-t-compiler/wg-mir-opt/topic/Dropping.20unused.20lock.20inside.20if.20let.html#218946578">(Dec 05 2020 at 18:24)</a>:</h4>
<p>You either need an upgradable lock, or you need to take the write lock to begin with, or you need a different primitive.</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>